package com.demo.esper.core;

import com.alibaba.fastjson.JSON;
import com.demo.esper.IEsper;
import com.demo.esper.IEsperConfig;
import com.demo.esper.event.AbstractEsperEvent;
import com.demo.esper.listener.EsperMatchedListener;
import com.demo.esper.result.EsperResult;
import com.demo.esper.statement.EsperRuleConfig;
import com.demo.service.EsperService;
import com.demo.uitls.SnowflakeUtil;
import com.demo.uitls.TransformerUtils;
import com.espertech.esper.client.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Component
public class EsperHandler implements IEsper, IEsperConfig {

    private final Logger logger = LoggerFactory.getLogger(EsperHandler.class);
    /**
     * esper相关数据存储服务
     */
    @Resource
    private EsperService esperService;

    /**
     * 获取statement数据
     *
     * @param ruleGroupName
     * @return
     */
    private List<EsperRuleConfig> getEsperRuleConfigList(String ruleGroupName) {
        return esperService.getEsperRuleConfigList(ruleGroupName);
    }

    /**
     * 初始化单个esper隔离区配置
     *
     * @param ruleGroupName
     * @param eventClass
     * @return
     */
    @Override
    public <T extends AbstractEsperEvent> EPServiceProviderIsolated initEPServiceIsolated(String eventTypeName, String ruleGroupName, Class<T> eventClass) {
        logger.info("ruleGroupName:{}, 初始化EPServiceIsolated", ruleGroupName);
        Configuration configuration = new Configuration();
        configuration.addEventType(eventTypeName, eventClass);
        configuration.getEngineDefaults().getExecution().setAllowIsolatedService(true);
        configuration.getEngineDefaults().getExecution().setPrioritized(true);
        EPServiceProvider provider = EPServiceProviderManager.getProvider(eventTypeName, configuration);
        try {
            EPServiceProviderIsolated providerIsolated = provider.getEPServiceIsolated(ruleGroupName);
            EPAdministratorIsolated adminIsolated = providerIsolated.getEPAdministrator();
            if (ArrayUtils.isEmpty(adminIsolated.getStatementNames())) {
                applyStatement(ruleGroupName, adminIsolated);
            }
            return providerIsolated;
        } catch (EPServiceDestroyedException e) {
            logger.error("ruleGroupName:{} destroyed", ruleGroupName);
        } catch (EPServiceNotAllowedException e) {
            logger.error("ruleGroupName:{} is not allowed", ruleGroupName);
        }
        logger.warn("ruleGroupName:{},初始化失败", ruleGroupName);
        return null;
    }

    private void applyStatement(String ruleGroupName, EPAdministratorIsolated adminIsolated) {
        List<EsperRuleConfig> ruleConfigList = getEsperRuleConfigList(ruleGroupName);
        if (CollectionUtils.isEmpty(ruleConfigList)) {
            logger.warn("ruleGroupName:{}, 找不到规则数据", ruleGroupName);
        }
        ruleConfigList.forEach(config -> {
            EPStatement statement = adminIsolated.createEPL(config.getStatement(), null, null);
            statement.addListener(new EsperMatchedListener());
        });
    }


    /**
     * 获取esper隔离区服务
     *
     * @param ruleGroupName
     * @return
     */
    private EPServiceProviderIsolated getEPServiceProviderIsolated(String eventTypeName, String ruleGroupName) {
        EPServiceProvider provider = EPServiceProviderManager.getProvider(eventTypeName);
        EPServiceProviderIsolated providerIsolated = provider.getEPServiceIsolated(ruleGroupName);
        return providerIsolated;
    }

    @Override
    public Long sendEvent(String eventTypeName, String ruleGroupName, AbstractEsperEvent pojoEvent) {
        Long eventId = SnowflakeUtil.INSTANCE.nextId();
        pojoEvent.setEventId(eventId);
        esperService.saveEsperRecord(eventId, ruleGroupName, pojoEvent);
        logger.info("----Esper send event start, eventId:{}, ruleGroupName:{}", eventId, ruleGroupName);
        logger.info("Esper data info, eventId:{}, ruleGroupName:{}，data:{}", eventId, ruleGroupName, JSON.toJSONString(pojoEvent));
        EPServiceProviderIsolated providerIsolated = getEPServiceProviderIsolated(eventTypeName, ruleGroupName);
        providerIsolated.getEPRuntime().sendEvent(pojoEvent);
        logger.info("----Esper send event end, eventId:{}, ruleGroupName:{}", eventId, ruleGroupName);
        return eventId;

    }

    @Override
    public <T extends EsperResult> T getEsperResult(Long eventId, Class<T> resultClass) {
        Map<String, Object> result = esperService.getEsperResult(eventId);
        if (result == null) {
            return null;
        }
        return TransformerUtils.INSTANCE.transformMap2Object(result, resultClass);
    }

}
